package lib4app;

import socket.DataField;
import socket.ProtocolMessage;
import struct.ActorInfo;
import struct.AppInfo;
import struct.SensorInfo;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import socket.AbstractTCP;
import socket.TCP;
import struct.*;
import struct.enums.CmdType;
import struct.enums.SensorMode;
import struct.enums.ServiceType;
import struct.ServiceInfo;
import util.Util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.IOException;
import java.net.Socket;
import java.util.*;

import static socket.CmdMessage.CMD_FIELD;

public class AppRemoteConnector {
    //单例模式
    private static AppRemoteConnector instance;
    private TCP tcp = null;
    private int udpPort = -1;
    private Log logger = LogFactory.getLog(AppRemoteConnector.class);
    private AbstractApp app = null;

    private AppRemoteConnector() {}

    public static AppRemoteConnector getInstance() {
        if (instance == null) {
            synchronized (AppRemoteConnector.class) {
                if (instance == null) {
                    instance = new AppRemoteConnector();
                }
            }
        }
        return instance;
    }

    public class AppRemoteConnectorTCP extends AbstractTCP {
        public AppRemoteConnectorTCP(Socket socket, boolean lockFlag) {
            super(socket, lockFlag);
        }

        public AppRemoteConnectorTCP(Socket socket) {
            super(socket);
        }

        @Override
        public void close() {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (app != null) {
                app.stopGetValueThread();
            }
        }

        @Override
        public void callback() {
            logger.info("[AppConnector]: TCP connection is broken.");
            if (app != null) {
                app.stopGetValueThread();
            }
            throw new PlatformException("TCP connection is broken.");
        }
    }

    public TCP getTCP() {
        return tcp;
    }

    public String getAppName() {
        return app.appName;
    }

    public String raw(String cmd) {
        tcp.send(cmd);
        String ret = tcp.recv();
        return ret;
    }

    public boolean connectPlatform(String ip, int port) {
        JSONObject jo = new JSONObject(1);
        jo.put(DataField.API_FIELD, ProtocolMessage.CONNECT_PLATFORM);
        boolean state = false;
        try {
            tcp = new AppRemoteConnectorTCP(new Socket(ip, port));
            tcp.send(jo.toJSONString());

            String recv = tcp.recv();
            if (recv != null) {
                JSONObject retJson = JSON.parseObject(recv);
                state = retJson.getBooleanValue(DataField.STATE_FIELD);
            }
        } catch (Exception e) {
            throw new PlatformException("Failed to connect to platform.");
        }
        logger.info(String.format("[AppConnector]: connectPlatform(%s, %d) -> %s", ip, port, state));
        return state;
    }

    public boolean disConnectPlatform() {
        JSONObject jo = new JSONObject(1);
        jo.put(DataField.API_FIELD, ProtocolMessage.DISCONNECT_PLATFORM);
        tcp.send(jo.toJSONString());

        boolean state = false;
        String recv = tcp.recv();
        if (recv != null) {
            JSONObject retJson = JSON.parseObject(recv);
            state = retJson.getBooleanValue(DataField.STATE_FIELD);
        }
        logger.info(String.format("[AppConnector]: disConnectPlatform() -> %s", state));
        if (state && app != null) {
            app.stopGetValueThread();
            app = null;
        }
        return state;
    }

    public boolean checkConnected() {
        JSONObject jo = new JSONObject(1);
        jo.put(DataField.API_FIELD, ProtocolMessage.CHECK_CONNECTED);
        tcp.send(jo.toJSONString());

        boolean state = false;
        String recv = tcp.recv();
        if (recv != null) {
            JSONObject retJson = JSON.parseObject(recv);
            state = retJson.getBooleanValue(DataField.STATE_FIELD);
        }
        logger.info(String.format("[AppConnector]: checkConnected() -> %s", state));
        return state;
    }

    public DBController getDBControllerInstance() {
        DBController dbController = DBController.getInstance();
        dbController.connector = this;
        return dbController;
    }

    public boolean registerApp(AbstractApp app) {
        JSONObject jo = new JSONObject(2);
        jo.put(DataField.API_FIELD, ProtocolMessage.REGISTER_APP);
        jo.put(AppInfo.APP_NAME_FIELD, app.appName);
        tcp.send(jo.toJSONString());

        boolean state = false;
        String recv = tcp.recv();
        if (recv != null) {
            JSONObject retJson = JSON.parseObject(recv);
            state = retJson.getBooleanValue(DataField.STATE_FIELD);
            if (state) {
                this.app = app;
                udpPort = retJson.getIntValue(DataField.PORT_FIELD);
            }
        }
        logger.info(String.format("[AppConnector]: registerApp(%s) -> %s", app.appName, state));
        return state;
    }

    public boolean unregisterApp(AbstractApp app) {
        JSONObject jo = new JSONObject(2);
        jo.put(DataField.API_FIELD, ProtocolMessage.UNREGISTER_APP);
        jo.put(AppInfo.APP_NAME_FIELD, app.appName);
        tcp.send(jo.toJSONString());

        boolean state = false;
        String recv = tcp.recv();
        if (recv != null) {
            JSONObject retJson = JSON.parseObject(recv);
            state = retJson.getBooleanValue(DataField.STATE_FIELD);
            if (state) {
                this.app.stopGetValueThread();
                this.app = null;
                udpPort = -1;
            }
        }
        logger.info(String.format("[AppConnector]: unregisterApp(%s) -> %s", app.appName, state));
        return state;
    }

    public Map<String, SensorInfo> getSupportedSensors() {
        JSONObject jo = new JSONObject(1);
        jo.put(DataField.API_FIELD, ProtocolMessage.GET_SUPPORTED_SENSORS);
        tcp.send(jo.toJSONString());

        JSONArray retJson = new JSONArray();
        String recv = tcp.recv();
        if (recv != null) {
            retJson = JSON.parseArray(recv);
        }
        Map<String, SensorInfo> ret = new HashMap<>();
        retJson.forEach(obj -> {
            JSONObject joo = (JSONObject) obj;
            ret.put(joo.getString(SensorInfo.SENSOR_NAME_FIELD), new SensorInfo(joo));
        });
        logger.info(String.format("[%s]: getSupportedSensors() -> %s", app.appName, ret));
        return ret;
    }

    public Map<String, SensorInfo> getRegisteredSensors() {
        JSONObject jo = new JSONObject(1);
        jo.put(DataField.API_FIELD, ProtocolMessage.GET_REGISTERED_SENSORS);
        jo.put(AppInfo.APP_NAME_FIELD, app.appName);
        tcp.send(jo.toJSONString());

        JSONArray retJson = new JSONArray();
        String recv = tcp.recv();
        if (recv != null) {
            retJson = JSON.parseArray(recv);
        }
        Map<String, SensorInfo> ret = new HashMap<>();
        retJson.forEach(obj -> {
            JSONObject joo = (JSONObject) obj;
            ret.put(joo.getString(SensorInfo.SENSOR_NAME_FIELD), new SensorInfo(joo));
        });
        logger.info(String.format("[%s]: getRegisteredSensors() -> %s", app.appName, ret));
        return ret;
    }

    public boolean getRegisteredSensorsStatus() {
        JSONObject jo = new JSONObject(2);
        jo.put(DataField.API_FIELD, ProtocolMessage.GET_REGISTERED_SENSORS_STATUS);
        jo.put(AppInfo.APP_NAME_FIELD, app.appName);
        tcp.send(jo.toJSONString());

        boolean state = false;
        String recv = tcp.recv();
        if (recv != null) {
            JSONObject retJson = JSON.parseObject(recv);
            state = retJson.getBooleanValue(DataField.STATE_FIELD);
        }
        logger.info(String.format("[%s]: getRegisteredSensorsStatus() -> %s", app.appName, state));
        return state;
    }

    public boolean registerSensor(String sensorName, SensorMode mode, int freq) {
        JSONObject jo = new JSONObject(4);
        jo.put(DataField.API_FIELD, ProtocolMessage.REGISTER_SENSOR);
        jo.put(AppInfo.APP_NAME_FIELD, app.appName);
        jo.put(SensorInfo.SENSOR_NAME_FIELD, sensorName);
        jo.put(DataField.MODE_FIELD, mode);
        jo.put(DataField.FREQ_FIELD, freq);
        tcp.send(jo.toJSONString());

        boolean state = false;
        String recv = tcp.recv();
        if (recv != null) {
            JSONObject retJson = JSON.parseObject(recv);
            state = retJson.getBooleanValue(DataField.STATE_FIELD);
        }
        logger.info(String.format("[%s]: registerSensor(%s,%s,%d) -> %s", app.appName, sensorName, mode, freq, state));
        return state;
    }

    public boolean cancelSensor(String sensorName) {
        JSONObject jo = new JSONObject(2);
        jo.put(DataField.API_FIELD, ProtocolMessage.CANCEL_SENSOR);
        jo.put(AppInfo.APP_NAME_FIELD, app.appName);
        jo.put(SensorInfo.SENSOR_NAME_FIELD, sensorName);
        tcp.send(jo.toJSONString());

        boolean state = false;
        String recv = tcp.recv();
        if (recv != null) {
            JSONObject retJson = JSON.parseObject(recv);
            state = retJson.getBooleanValue(DataField.STATE_FIELD);
        }
        logger.info(String.format("[%s]: cancelSensor(%s) -> %s", app.appName, sensorName, state));
        return state;
    }

    public boolean cancelAllSensors() {
        JSONObject jo = new JSONObject(1);
        jo.put(DataField.API_FIELD, ProtocolMessage.CANCEL_ALL_SENSORS);
        jo.put(AppInfo.APP_NAME_FIELD, app.appName);
        tcp.send(jo.toJSONString());

        boolean state = false;
        String recv = tcp.recv();
        if (recv != null) {
            JSONObject retJson = JSON.parseObject(recv);
            state = retJson.getBooleanValue(DataField.STATE_FIELD);
        }
        logger.info(String.format("[%s]: cancelAllSensors() -> %s", app.appName, state));
        return state;
    }

    public SensorData getSensorData(String sensorName) {
        JSONObject jo = new JSONObject(2);
        jo.put(DataField.API_FIELD, ProtocolMessage.GET_SENSOR_DATA);
        jo.put(AppInfo.APP_NAME_FIELD, app.appName);
        jo.put(SensorInfo.SENSOR_NAME_FIELD, sensorName);
        tcp.send(jo.toJSONString());

        String recv = tcp.recv();
        SensorData ret = SensorData.defaultErrorData();
        if (recv != null) {
            ret = SensorData.fromJSONString(recv);
        }

        logger.info(String.format("[%s]: getSensorData(%s) -> %s", app.appName, sensorName, ret));
        return ret;
    }

    public Map<String, SensorData> getAllSensorData() {
        Map<String, SensorData> ret = new HashMap<>();
        JSONObject jo = new JSONObject(1);
        jo.put(DataField.API_FIELD, ProtocolMessage.GET_ALL_SENSOR_DATA);
        jo.put(AppInfo.APP_NAME_FIELD, app.appName);
        tcp.send(jo.toJSONString());

        JSONArray ja = new JSONArray();
        String recv = tcp.recv();
        if (recv != null) {
            ja = JSON.parseArray(recv);
        }
        for (Object obj : ja) {
            JSONObject joo = (JSONObject) obj;
            ret.put(joo.getString(SensorInfo.SENSOR_NAME_FIELD), SensorData.fromJSONString(joo.getString(DataField.VALUE_FIELD)));
        }
        logger.info(String.format("[%s]: getAllSensorData() -> %s", app.appName, ret));
        return ret;
    }

    public boolean getMsgThread(CmdType cmd) {
        boolean state = false;
        if (udpPort != -1) {
            JSONObject jo = new JSONObject(2);
            jo.put(DataField.API_FIELD, ProtocolMessage.GET_MSG_THREAD);
            jo.put(AppInfo.APP_NAME_FIELD, app.appName);
            jo.put(CMD_FIELD, cmd);
            tcp.send(jo.toJSONString());

            state = false;
            String recv = tcp.recv();
            if (recv != null) {
                JSONObject retJson = JSON.parseObject(recv);
                state = retJson.getBooleanValue(DataField.STATE_FIELD);
            }
            if (state) {
                if (cmd == CmdType.START) {
                    this.app.startGetValueThread(udpPort);
                } else if (cmd == CmdType.STOP) {
                    this.app.stopGetValueThread();
                }
            }
        }
        logger.info(String.format("[%s]: getMsgThreadState(%s) -> %s", app.appName, cmd, state));
        return state;
    }

    public Map<String, ActorInfo> getSupportedActors() {
        JSONObject jo = new JSONObject(1);
        jo.put(DataField.API_FIELD, ProtocolMessage.GET_SUPPORTED_ACTORS);
        tcp.send(jo.toJSONString());

        JSONArray retJson = new JSONArray();
        String recv = tcp.recv();
        if (recv != null) {
            retJson = JSON.parseArray(recv);
        }
        Map<String, ActorInfo> ret = new HashMap<>();
        retJson.forEach(obj -> {
            JSONObject joo = (JSONObject) obj;
            ret.put(joo.getString(ActorInfo.ACTOR_NAME_FIELD), new ActorInfo(joo));
        });
        logger.info(String.format("[%s]: getSupportedActors() -> %s", app.appName, ret));
        return ret;
    }

    public Map<String, ActorInfo> getRegisteredActors() {
        JSONObject jo = new JSONObject(1);
        jo.put(DataField.API_FIELD, ProtocolMessage.GET_REGISTERED_ACTORS);
        jo.put(AppInfo.APP_NAME_FIELD, app.appName);
        tcp.send(jo.toJSONString());

        JSONArray retJson = new JSONArray();
        String recv = tcp.recv();
        if (recv != null) {
            retJson = JSON.parseArray(recv);
        }
        Map<String, ActorInfo> ret = new HashMap<>();
        retJson.forEach(obj -> {
            JSONObject joo = (JSONObject) obj;
            ret.put(joo.getString(ActorInfo.ACTOR_NAME_FIELD), new ActorInfo(joo));
        });
        logger.info(String.format("[%s]: getRegisteredActors() -> %s", app.appName, ret));
        return ret;
    }

    public boolean getRegisteredActorsStatus() {
        JSONObject jo = new JSONObject(1);
        jo.put(DataField.API_FIELD, ProtocolMessage.GET_REGISTERED_ACTORS_STATUS);
        jo.put(AppInfo.APP_NAME_FIELD, app.appName);
        tcp.send(jo.toJSONString());

        boolean state = false;
        String recv = tcp.recv();
        if (recv != null) {
            JSONObject retJson = JSON.parseObject(recv);
            state = retJson.getBooleanValue(DataField.STATE_FIELD);
        }
        logger.info(String.format("[%s]: getRegisteredActorStatus() -> %s", app.appName, state));
        return state;
    }

    public boolean registerActor(String actorName) {
        JSONObject jo = new JSONObject(2);
        jo.put(DataField.API_FIELD, ProtocolMessage.REGISTER_ACTOR);
        jo.put(AppInfo.APP_NAME_FIELD, app.appName);
        jo.put(ActorInfo.ACTOR_NAME_FIELD, actorName);
        tcp.send(jo.toJSONString());

        boolean state = false;
        String recv = tcp.recv();
        if (recv != null) {
            JSONObject retJson = JSON.parseObject(recv);
            state = retJson.getBooleanValue(DataField.STATE_FIELD);
        }
        logger.info(String.format("[%s]: registerActor(%s) -> %s", app.appName, actorName, state));
        return state;
    }

    public boolean cancelActor(String actorName) {
        JSONObject jo = new JSONObject(2);
        jo.put(DataField.API_FIELD, ProtocolMessage.CANCEL_ACTOR);
        jo.put(AppInfo.APP_NAME_FIELD, app.appName);
        jo.put(ActorInfo.ACTOR_NAME_FIELD, actorName);
        tcp.send(jo.toJSONString());

        boolean state = false;
        String recv = tcp.recv();
        if (recv != null) {
            JSONObject retJson = JSON.parseObject(recv);
            state = retJson.getBooleanValue(DataField.STATE_FIELD);
        }
        logger.info(String.format("[%s]: cancelActor(%s) -> %s", app.appName, actorName, state));
        return state;
    }

    public boolean cancelAllActors() {
        JSONObject jo = new JSONObject(1);
        jo.put(DataField.API_FIELD, ProtocolMessage.CANCEL_ALL_ACTORS);
        jo.put(AppInfo.APP_NAME_FIELD, app.appName);
        tcp.send(jo.toJSONString());

        boolean state = false;
        String recv = tcp.recv();
        if (recv != null) {
            JSONObject retJson = JSON.parseObject(recv);
            state = retJson.getBooleanValue(DataField.STATE_FIELD);
        }
        logger.info(String.format("[%s]: cancelAllActors() -> %s", app.appName, state));
        return state;
    }

    public boolean sendActorCmd(String actorName, String action) {
        JSONObject jo = new JSONObject(3);
        jo.put(DataField.API_FIELD, ProtocolMessage.SEND_ACTOR_CMD);
        jo.put(AppInfo.APP_NAME_FIELD, app.appName);
        jo.put(ActorInfo.ACTOR_NAME_FIELD, actorName);
        jo.put(DataField.ACTION_FIELD, action);
        tcp.send(jo.toJSONString());

        boolean state = false;
        String recv = tcp.recv();
        if (recv != null) {
            JSONObject retJson = JSON.parseObject(recv);
            state = retJson.getBooleanValue(DataField.STATE_FIELD);
        }
        logger.info(String.format("[%s]: setActorCmd(%s, %s) -> %s", app.appName, actorName, action, state));
        return state;
    }

    public boolean isServiceOn(ServiceType service) {
        JSONObject jo = new JSONObject(2);
        jo.put(DataField.API_FIELD, ProtocolMessage.IS_SERVICE_ON);
        jo.put(AppInfo.APP_NAME_FIELD, app.appName);
        jo.put(ServiceInfo.SERVICE_TYPE_FIELD, service.toString());
        tcp.send(jo.toJSONString());

        boolean state = false;
        String recv = tcp.recv();
        if (recv != null) {
            JSONObject retJson = JSON.parseObject(recv);
            state = retJson.getBooleanValue(DataField.STATE_FIELD);
        }
        logger.info(String.format("[%s]: isServerOn(%s) -> %s", app.appName, service, state));
        return state;
    }

    public boolean serviceStart(ServiceType service, ServiceConfig config) {
        if (service == ServiceType.INV || service == ServiceType.ALL) {
            InvCheck invCheck = InvCheck.getInstance();
            invCheck.connector = this;
            invCheck.init((InvServiceConfig) config);
        }

        JSONObject jo = new JSONObject(3);
        jo.put(DataField.API_FIELD, ProtocolMessage.SERVICE_START);
        jo.put(AppInfo.APP_NAME_FIELD, app.appName);
        jo.put(ServiceInfo.SERVICE_TYPE_FIELD, service.toString());
        jo.put(ServiceInfo.SERVICE_CONFIG_FIELD, config.toJSONString());
        tcp.send(jo.toJSONString());

        boolean state = false;
        String recv = tcp.recv();
        if (recv != null) {
            JSONObject retJson = JSON.parseObject(recv);
            state = retJson.getBooleanValue(DataField.STATE_FIELD);
        }
        logger.info(String.format("[%s]: serviceStart(%s,%s) -> %s", app.appName, service, config, state));
        return state;
    }

    public boolean serviceStop(ServiceType service) {
        if (service == ServiceType.INV || service == ServiceType.ALL) {
            InvCheck invCheck = InvCheck.getInstance();
            invCheck.connector = null;
        }

        JSONObject jo = new JSONObject(2);
        jo.put(DataField.API_FIELD, ProtocolMessage.SERVICE_STOP);
        jo.put(AppInfo.APP_NAME_FIELD, app.appName);
        jo.put(ServiceInfo.SERVICE_TYPE_FIELD, service.toString());
        tcp.send(jo.toJSONString());

        boolean state = false;
        String recv = tcp.recv();
        if (recv != null) {
            JSONObject retJson = JSON.parseObject(recv);
            state = retJson.getBooleanValue(DataField.STATE_FIELD);
        }
        logger.info(String.format("[%s]: serviceStop(%s) -> %s", app.appName, service, state));
        return state;
    }

    public boolean serviceCall(ServiceType service, CmdType cmd, ServiceConfig config) {
        if (service == ServiceType.INV || service == ServiceType.ALL) {
            InvCheck invCheck = InvCheck.getInstance();
            if (cmd == CmdType.START) {
                invCheck.connector = this;
                invCheck.init((InvServiceConfig) config);
            } else if (cmd == CmdType.STOP) {
                invCheck.connector = null;
            }
        }

        JSONObject jo = new JSONObject(4);
        jo.put(DataField.API_FIELD, ProtocolMessage.SERVICE_CALL);
        jo.put(AppInfo.APP_NAME_FIELD, app.appName);
        jo.put(ServiceInfo.SERVICE_TYPE_FIELD, service.toString());
        jo.put(DataField.CMD_TYPE_FIELD, cmd.toString());
        if (config != null) {
            jo.put(ServiceInfo.SERVICE_CONFIG_FIELD, config.toJSONString());
        }
        tcp.send(jo.toJSONString());

        boolean state = false;
        String recv = tcp.recv();
        if (recv != null) {
            JSONObject retJson = JSON.parseObject(recv);
            state = retJson.getBooleanValue(DataField.STATE_FIELD);
        }
        logger.info(String.format("[%s]: serviceCall(%s, %s, %s) -> %s", app.appName, service, cmd, config, state));
        return state;
    }

    public SensorInfo getSensorInfo(String sensorName) {
        JSONObject jo = new JSONObject(2);
        jo.put(DataField.API_FIELD, ProtocolMessage.GET_SENSOR_INFO);
        jo.put(SensorInfo.SENSOR_NAME_FIELD, sensorName);
        tcp.send(jo.toJSONString());

        String recv = tcp.recv();
        SensorInfo ret = null;
        if (recv != null) {
            ret = new SensorInfo(JSON.parseObject(recv));
        }
        logger.info(String.format("[%s]: getSensorInfo(%s) -> %s", app.appName, sensorName, ret));
        return ret;
    }

    public String getSensorInfoAndData(String sensorName) {
        JSONObject jo = new JSONObject(2);
        jo.put(DataField.API_FIELD, ProtocolMessage.GET_SENSOR_INFO_AND_DATA);
        jo.put(SensorInfo.SENSOR_NAME_FIELD, sensorName);
        tcp.send(jo.toJSONString());

        String recv = tcp.recv();
        logger.info(String.format("[%s]: getSensorInfoAndData(%s) -> %s", app.appName, sensorName, recv));
        return recv;
    }

    public Map<String, SensorInfo> getAllSensorInfo() {
        Map<String, SensorInfo> ret = new HashMap<>();
        JSONObject jo = new JSONObject(1);
        jo.put(DataField.API_FIELD, ProtocolMessage.GET_ALL_SENSOR_INFO);
        tcp.send(jo.toJSONString());

        JSONArray ja = new JSONArray();
        String recv = tcp.recv();
        if (recv != null) {
            ja = JSON.parseArray(recv);
        }
        for (Object obj : ja) {
            JSONObject joo = (JSONObject) obj;
            ret.put(joo.getString(SensorInfo.SENSOR_NAME_FIELD), new SensorInfo(joo));
        }
        logger.info(String.format("[%s]: getAllSensorInfo() -> %s", app.appName, ret));
        return ret;
    }

    public Map<String, String> getAllSensorInfoAndData() {
        Map<String, String> ret = new HashMap<>();
        JSONObject jo = new JSONObject(1);
        jo.put(DataField.API_FIELD, ProtocolMessage.GET_ALL_SENSOR_INFO_AND_DATA);
        tcp.send(jo.toJSONString());

        JSONArray ja = new JSONArray();
        String recv = tcp.recv();
        if (recv != null) {
            ja = JSON.parseArray(recv);
        }
        for (Object obj : ja) {
            JSONObject joo = (JSONObject) obj;
            ret.put(joo.getString(SensorInfo.SENSOR_NAME_FIELD), joo.toJSONString());
        }
        logger.info(String.format("[%s]: getAllSensorInfoAndData() -> %s", app.appName, ret));
        return ret;
    }

    public ActorInfo getActorInfo(String actorName) {
        JSONObject jo = new JSONObject(2);
        jo.put(DataField.API_FIELD, ProtocolMessage.GET_ACTOR_INFO);
        jo.put(ActorInfo.ACTOR_NAME_FIELD, actorName);
        tcp.send(jo.toJSONString());

        ActorInfo ret = null;
        String recv = tcp.recv();
        if (recv != null) {
            JSONObject retJson = JSON.parseObject(recv);
            ret = new ActorInfo(retJson);
        }
        logger.info(String.format("[%s]: getActorInfo(%s) -> %s", app.appName, actorName, ret));
        return ret;
    }

    public Map<String, ActorInfo> getAllActorInfo() {
        Map<String, ActorInfo> ret = new HashMap<>();
        JSONObject jo = new JSONObject(1);
        jo.put(DataField.API_FIELD, ProtocolMessage.GET_ALL_ACTOR_INFO);
        tcp.send(jo.toJSONString());

        JSONArray ja = new JSONArray();
        String recv = tcp.recv();
        if (recv != null) {
            ja = JSON.parseArray(recv);
        }
        for (Object obj : ja) {
            JSONObject joo = (JSONObject) obj;
            ret.put(joo.getString(ActorInfo.ACTOR_NAME_FIELD), new ActorInfo(joo));
        }
        logger.info(String.format("[%s]: getAllActorInfo() -> %s", app.appName, ret));
        return ret;
    }

    public AppInfo getAppInfo() {
        JSONObject jo = new JSONObject(1);
        jo.put(DataField.API_FIELD, ProtocolMessage.GET_APP_INFO);
        jo.put(AppInfo.APP_NAME_FIELD, app.appName);
        tcp.send(jo.toJSONString());

        AppInfo ret = null;
        String recv = tcp.recv();
        if (recv != null) {
            JSONObject retJson = JSON.parseObject(recv);
            ret = new AppInfo(retJson);
        }
        logger.info(String.format("[%s]: getAppInfo() -> %s", app.appName, ret));
        return ret;
    }

    public Map<String, AppInfo> getAllAppInfo() {
        Map<String, AppInfo> ret = new HashMap<>();
        JSONObject jo = new JSONObject(1);
        jo.put(DataField.API_FIELD, ProtocolMessage.GET_ALL_APP_INFO);
        tcp.send(jo.toJSONString());

        JSONArray ja = new JSONArray();
        String recv = tcp.recv();
        if (recv != null) {
            ja = JSON.parseArray(recv);
        }
        for (Object obj : ja) {
            JSONObject joo = (JSONObject) obj;
            ret.put(joo.getString(AppInfo.APP_NAME_FIELD), new AppInfo(joo));
        }
        logger.info(String.format("[%s]: getAllAppInfo() -> %s", app.appName, ret));
        return ret;
    }

    public ServiceInfo getServiceInfo(ServiceType service) {
        JSONObject jo = new JSONObject(2);
        jo.put(DataField.API_FIELD, ProtocolMessage.GET_SERVICE_INFO);
        jo.put(AppInfo.APP_NAME_FIELD, app.appName);
        jo.put(ServiceInfo.SERVICE_TYPE_FIELD, service.toString());
        tcp.send(jo.toJSONString());

        ServiceInfo ret = null;
        String recv = tcp.recv();
        if (recv != null) {
            JSONObject retJson = JSON.parseObject(recv);
            ret = new ServiceInfo(retJson);
        }
        logger.info(String.format("[%s]: getServiceInfo(%s) -> %s", app.appName, service, ret));
        return ret;
    }

    public boolean setUI(String jspUrl, String dslFile) { //jspUrl: a/b/c.jsp dslFile: d.html
        boolean state = false;
        JSONObject jo = new JSONObject(4);
        jo.put(DataField.API_FIELD, ProtocolMessage.SET_UI);
        jo.put(AppInfo.APP_NAME_FIELD, app.appName);
        jo.put(DataField.JSP_URL_FIELD, jspUrl);
        String content = Util.readFileContent(dslFile, "//quota");
        if (content != null) {
            jo.put(DataField.DSL_FIELD, content);
            tcp.send(jo.toJSONString());

            String recv = tcp.recv();
            if (recv != null) {
                JSONObject retJson = JSON.parseObject(recv);
                state = retJson.getBooleanValue(DataField.STATE_FIELD);
            }
        }
        logger.info(String.format("[%s]: setUI(%s, %s) -> %s", app.appName, jspUrl, dslFile, state));
        return state;
    }
}
